package net.shambolica.ember.jinterface.wrappers.objects;

import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import net.shambolica.ember.jinterface.wrappers.objects.patterns.*;

import java.util.ArrayList;
import java.util.List;

/**
 * Patterns factory.
 */
public class EOP {

    /**
     * Constant pattern: represents a term.
     * @param term  The object to represent.
     * @return      The pattern.
     */
    public static EOPattern pterm(OtpErlangObject term) {
        return new EOPTerm(term);
    }


    public static EOPattern pvar(String varName) {
        return new EOPVar(varName);
    }
    

    /* Predicates */

    public static EOPattern pequals(OtpErlangObject term) {
        return pterm(term);
    }

    public static EOPattern pnot(EOPattern pattern) {
        return new EOPNot(pattern);
    }

    public static EOPattern pand(EOPattern left, EOPattern right) {
        return new EOPAnd(left, right);
    }

    public static EOPattern por(EOPattern left, EOPattern right) {
        return new EOPOr(left, right);
    }

    public static EOPattern plength_eq(int length) {
        return new EOPLength(EOPLength.OP_EQ, length);
    }

    public static EOPattern pis_atom() {
        return EOPIsA.isAtom;
    }

    public static EOPattern pis_binary() {
        return EOPIsA.isBinary;
    }

    public static EOPattern pis_number() {
        return EOPIsA.isNumber;
    }

    public static EOPattern pis_list() {
        return EOPIsA.isList;
    }

    public static EOPattern pis_pid() {
        return EOPIsA.isPid;
    }

    public static EOPattern pis_ref() {
        return EOPIsA.isRef;
    }

    public static EOPattern pis_tuple() {
        return EOPIsA.isTuple;
    }


    /* TODO: Direct term creation wrappers? */

    private static final EOPattern pList = pand(pis_list(), plength_eq(0));
    private static final EOPattern pTuple = pand(pis_tuple(), plength_eq(0));

    public static EOPattern plist() {
        return pList;
    }

    public static EOPattern plist(Object ... elems) {
        return pseq(plist(), elems);
    }

    public static EOPattern ptuple() {
        return pTuple;
    }

    public static EOPattern ptuple(Object ... elems) {
        return pseq(ptuple(), elems);
    }

    private static EOPattern pseq(EOPattern first, Object ... elems) {
        if (elems.length == 0) {
            return first;
        } else {
            EOPattern last = first;
            for (Object it: elems) {
                last = new EOPAnd(last, asPattern(it));
            }
            return last;
        }
    }

    public static EOPattern asPattern(Object it) {
        if (it instanceof OtpErlangObject) {
            return pterm((OtpErlangObject)it);
        } else if (it instanceof EOPattern) {
            return ((EOPattern)it);
        } else {
            throw new ClassCastException("object not Erlang object or pattern");
        }
    }

}
